#include "astralapi.h"
#include "queueapi.h"
#include "_2task.h"
#include "strapi.h"
#include "task.h"

#ifndef CFG_TASK_NUM
#define CFG_TASK_NUM 100
#endif

typedef struct TaskWapper {
    AstralTask task;
    /**
     * @brief global suspended qeue
     *         for task info query.
     */
    struct QueueNode  suspend_nd;
    struct QueueNode  creation_nd;

    /**
     * @brief detail list for the event
     *          which caused task got blocked.
     */
    struct QueueNode  blocked_on;
} *TaskWapper;


static TaskWapper get_task_wrapper(int id)
{
    static struct TaskWapper tw_array[CFG_TASK_NUM];
    return &tw_array[id];
}


#define arch_build_stack_frame(p,e, a) \
        arch_build_stack_frame(CAST_AS(StackPointer,p), CAST_AS(address, e), a)



static int get_task_id()
{
    static int gTaskIdentifier = 0;
    return ++gTaskIdentifier;
}


/***************************************************************************************/
/**                               Task Manage API Inside  Kernel                      **/
/***************************************************************************************/



DEFINE_QUEUE(task_created)


AstralTask get_next_task(AstralTask curr)
{
    TaskWapper tw = NULL;
    QueueNode  n = task_created->first;
    if(!curr)
    {
        tw = CONTAINER_OF(TaskWapper, creation_nd, n);
    }
    else
    {
        tw = get_task_wrapper(curr->id);
        n = tw->creation_nd.next;
        tw = CONTAINER_OF(TaskWapper, creation_nd, n);
    }
    if(!tw)
    {
        return NULL;
    }
    return tw->task;
}

void list_thread()
{
    AstralTask get_next_task(AstralTask curr);

    AstralTask curr = get_next_task(NULL);
    kprint("%10s %10s %5s %10s %6s %6s %10s\n", "TaskID", "Name", "Prio", "status", "run", "Core", "Address");
    while (curr)
    {
        kprint("  %8d %10s %5d %10s %5d %-5d %p  ",
               curr->id,
               curr->name,
               curr->priority,
               get_task_status(curr),
               curr->run_times,
               curr->core,
               curr);
        kprint("\n");
        curr = get_next_task(curr);
    }
}

/***************************************************************************************/
/**                               Task Manage API for  KApp                           **/
/***************************************************************************************/


void create_task(AstralTask task,
                 AstralAttr attr,
                 runable entry,
                 object arg)
{
    task->task_type = KTASK;
    task->entry = entry;
    task->param = arg;
    task->priority = attr->priority;
    task->ksp_bot = attr->base;
    // align to word
    task->ksp_top = attr->base + attr->stack_size - 1;
    task->method = PRIO;

    task->slice_work = task->slice = 20;
    task->affinity = CFG_CORE_NUM;
    task->core = CFG_CORE_NUM;

    // enter_system_critical();
    queue_init(&task->childs);
    AstralTask p = get_curr_task();
    task->parent  = p;
    if(p)
    {
        queue_push(&p->childs, &task->tree);
    }

    task->id = get_task_id();
    task->ksp = arch_build_stack_frame(
        task->ksp_top,
        kernel_task_entry,
        task);

    if (!attr->name)
    {
        snprintf(task->name, 15, "task%d", task->id);
    }
    else
    {
        strncpy(task->name, attr->name, 15);
    }
    task->released = True;

    TaskWapper tw = get_task_wrapper(task->id);
    queue_push(task_created, &tw->creation_nd);
    tw->task = task;


    state_change(task, CREATED, False);

    // exit_system_critical();
}

boolean distach_task(AstralTask task)
{
    if(task->status != CREATED)
    {
        return False;
    }
    state_change(task, RESUMED, False);
    return False;
}


void yeild_task()
{
    AstralTask self = get_curr_task();
    state_change(self, SLICEUP, True);
}


